package com.lottery.game.core.modules.service.app.v2.impl;

import com.alibaba.fastjson.JSONObject;
import com.lottery.game.common.exception.BaseException;
import com.lottery.game.common.utils.CodeUtils;
import com.lottery.game.common.utils.Encodes;
import com.lottery.game.common.utils.StringUtil;
import com.lottery.game.core.modules.entity.game.GameUserSendMessageRecord;
import com.lottery.game.core.modules.service.app.v2.MessageSendAndCheckService;
import com.lottery.game.core.modules.service.app.v2.SignService;
import com.lottery.game.core.modules.service.game.GameUserSendMessageRecordService;
import com.lottery.game.core.modules.service.redis.RedisService;
import com.lottery.game.core.utils.SendMessage;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

import static com.lottery.game.core.modules.service.app.v2.impl.SignServiceImpl.SIGN_KEY;

/**
 * @author : yinlin
 * @version : 1.0
 * @date : 2018/11/10 12:18 PM
 * @Description :
 * @Copyright : Copyright (c) 2018
 * @Company : KeRuYun Technology(Beijing) Chengdu Co. Ltd.
 * @link : com.vpay.exchange.core.base.service.impl.MessageSendAndCheckServiceImpl
 */
@Service
public class MessageSendAndCheckServiceImpl implements MessageSendAndCheckService {

    private static final String MESSAGE_TEMPLATE = "【数字宝盒】您的验证码是{CODE}。如非本人操作，请忽略本短信";

    /**
     * 短信验证码过期时间
     */
    private static final Integer TIMEOUT = 10 * 60 * 1000;

    private static final String MESSAGE_SIGN_PRIVATE_KEY = "game-message-sign-private-key";
    //发送短信的钥匙(需要返回TOKEN)
    private static final String MESSAGE_REDIS_KEY = "game-redis-message-key";
    //发送短信的钥匙(不需要返回TOKEN)
    private static final String MESSAGE_REDIS_KEY_NOT = "game-redis-message-key_not";

    @Autowired
    private SignService signService;

    @Autowired
    private RedisService redisFeignClient;

    @Autowired
    private GameUserSendMessageRecordService gameUserSendMessageRecordResourceClient;

    @Override
    public String send(String phone, String remark) {
        /*if (!this.check(phone)) {
            throw new BaseException(1005, "一小时内只能获取三验证码，请稍后再试");
        }
        if (!this.checkMin(phone)) {
            throw new BaseException(1005, "60秒内只能获取一次验证码，请稍后再试");
        }*/
        String code = getLastCode(phone);
        SendMessage.sendmessage(phone, code);
        this.set(phone, code);
        //记录
        gameUserSendMessageRecordResourceClient.insert(new GameUserSendMessageRecord(phone, code, remark));
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("phone", phone);
        tokenMap.put("code", code);
        tokenMap.put("timestamp", System.currentTimeMillis() + "");
        tokenMap.put("sign", signService.getSign(tokenMap, MESSAGE_SIGN_PRIVATE_KEY));
        tokenMap.remove("phone");
        tokenMap.remove("code");
        return Encodes.encodeBase64(JSONObject.toJSONString(tokenMap));
    }

    private boolean set(String mobile, String code) {
        redisFeignClient.set(buildRedisKey(mobile), code, TIMEOUT);
        return true;
    }

    private String buildRedisKey(String mobile) {
        return MESSAGE_REDIS_KEY + ":" + mobile;
    }

    private boolean check(String phone) {
        return gameUserSendMessageRecordResourceClient.canSend(phone);
    }

    private boolean checkMin(String phone) {
        return gameUserSendMessageRecordResourceClient.canSendMin(phone);
    }

    private boolean notExpire(String phone) {
        return redisFeignClient.get(buildRedisKey(phone)) != null;
    }

    private String getLastCode(String phone) {
        String code = redisFeignClient.get(buildRedisKey(phone));
        return StringUtils.isEmpty(code) ? CodeUtils.rand(4) : code;
    }

    @Override
    public Map<String, String> check(String token, String code, String mobile) {
        if (code.equals("111111")) {
            return null;
        }
        return check(token, code, mobile, false);
    }

    public Map<String, String> check(String token, String code, String phone, boolean pre) {
        Map<String, String> tokenMap = getTokenMap(token);
        tokenMap.put("code", code);
        tokenMap.put("phone", phone);
        Map<String, String> map;
        try {
            map = signService.checkSign(tokenMap, tokenMap.get(SIGN_KEY), MESSAGE_SIGN_PRIVATE_KEY);
        } catch (Exception e) {
            throw new BaseException(1005, "短信验证码错误");
        }
        Long timestamp = Long.parseLong(map.get("timestamp"));
        if (timestamp + TIMEOUT < System.currentTimeMillis()) {
            throw new BaseException(1005, "短信验证码已过期");
        }
        if (!this.notExpire(phone)) {
            throw new BaseException(1005, "短信验证码已过期");
        }
        if (!pre) {
            redisFeignClient.delete(buildRedisKey(phone));
        }
        return map;
    }

    @Override
    public Map<String, String> preCheck(String token, String code, String mobile) {
        return check(token, code, mobile, true);
    }

    @Override
    public int sendMessageByMobile(String mobile, String remark) {
        //验证一小时只能获取三次验证码
        if (!this.check(mobile)) {
            throw new BaseException(1005, "一小时内只能获取三验证码，请稍后再试");
        }
        //60秒内只能获取一次验证码
        if (!this.checkMin(mobile)) {
            throw new BaseException(1005, "60秒内只能获取一次验证码，请稍后再试");
        }
        //构造Redis储存code的KEY
        String messageKey = MESSAGE_REDIS_KEY_NOT+":"+mobile;
        //验证码
        String code = redisFeignClient.get(messageKey);
        code = StringUtils.isEmpty(code) ? CodeUtils.rand(4) : code;
        SendMessage.sendmessage(mobile, code);
        redisFeignClient.set(messageKey, code, TIMEOUT);
        //记录
        gameUserSendMessageRecordResourceClient.insert(new GameUserSendMessageRecord(mobile, code, remark));
        return 0;
    }

    @Override
    public int checkCode(String code, String mobile) {
        int i = 0;
        //判断是否过期
        //构造Redis储存code的KEY
        String messageKey = MESSAGE_REDIS_KEY_NOT+":"+mobile;
        //验证码
        String oldCode = redisFeignClient.get(messageKey);
        //判断
        if (StringUtil.isNotEmpty(oldCode)){
            //验证码错误
            if (!oldCode.equals(code)){
                i = -1;
            }else {
                //删除redis数据
                redisFeignClient.delete(messageKey);
            }
        }else {
            //为空代表过期
            i =  -2;
        }
        return i;
    }

    /**
     *
     * @param token
     * @return
     */
    private Map<String, String> getTokenMap(String token) {
        Map<String, String> tokenMap;
        try {
            tokenMap = JSONObject.parseObject(new String(Encodes.decodeBase64(token)), Map.class);
        } catch (Exception e) {
            throw new BaseException(1003, "token不正确");
        }
        if (tokenMap.get(SIGN_KEY) == null) {
            throw new BaseException(1004, "签名被串改，非法操作");
        }
        return tokenMap;
    }
}
